home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #23 (Aug 87) / Dont panic source / DON'T PANIC code.c < prev    next >
Text File  |  1987-04-19  |  18KB  |  690 lines

  1. /*
  2.  
  3.     File:
  4.             "Don't Panic"    
  5.                 an AppleTalk application
  6.  
  7.     By:
  8.             Ty Shipman,  Gorilla Software Systems
  9.             April 11, 1987
  10.  
  11.     For:        General Public using LightSpeed C
  12.  
  13.  
  14.         (C) Copyright 1987 Ty Shipman
  15.         All Rights Resereved.
  16.         This notice must appear in all copies.  Commerical use of
  17.         this code forbidden, without prior written
  18.         permission of the author.
  19.  
  20. */
  21.  
  22. #include "MacTypes.h"
  23. #include "DialogMgr.h"
  24. #include "EventMgr.h"
  25. #include "ControlMgr.h"
  26. #include "Appletalk.h"
  27.  
  28. #include "DON'T PANIC.h"
  29.  
  30.  
  31.     /* all the globals*/
  32.  
  33.     CurEntity            NowEntity;    /* the current selected target for request */
  34.  
  35.  
  36.     char            *ErrMess;        /* a pointer to a possible error message */
  37.     ABRecHandle        atpRec;            /* handle to the above */
  38.     Str255            atpRecBuf;        /* to hold request data in */
  39.  
  40.     int                RecSocket;        /* the socket I receive requests through */
  41.     char            LUBuffer[2000];    /* my lookup buffer */
  42.     int                Extractwhere;        /* the current place in the extract list */
  43.  
  44.     ABRecHandle        myABRecord;        /* for my mac reg on net */
  45.     EntityName        myEntity;            /* used to store my name,type,zone on */
  46.     char            myEBuff[105];        /* this is a wasted space, max is 105 */
  47.  
  48.     ABRecHandle        Responce;            /* for the responce stuff */
  49.     BDSElement        RspBDS;
  50.      char            *BDSmess = "\pI recieved your message, requester";
  51.  
  52.     BDSPtr            myBDSPtr;        /* used in the request stuff */
  53.     BDSElement        myBDS;            /* used to reference the responce */
  54.     char            mysBuffer[512];    /* store the responce here */
  55.     ABRecHandle        SendRec;
  56.  
  57.     /* end of globals */
  58.  
  59. extern    DialogPtr        myWindow;
  60.  
  61. doAlloc()
  62. {
  63.         /* this routine will allocate all the records needed */
  64.  
  65.  
  66.     myABRecord = (ABRecHandle)NewHandle(sizeof(ABusRecord)); /* for my mac reg on net */
  67.  
  68.     Responce = (ABRecHandle)NewHandle(sizeof(ABusRecord));
  69.  
  70.     SendRec = (ABRecHandle)NewHandle(sizeof(ABusRecord));
  71. }
  72.  
  73.  
  74. ATCheck()
  75. {
  76.     char    *PortBUseP;        /* a pointer to PortBUse Byte */
  77.     char    *SPConfigP;        /* SerialPortConfiguration byte */
  78.     char    use,con;            /* storage for pointer contence*/
  79.     int        error;
  80.  
  81.     /*    this routine will check to see if the port is set up for
  82.         AppleTalk. It will also load the ATP, NBP, and
  83.         any other packages necessary for AppleTalk.
  84.     */
  85.  
  86.     CouldDialog(ERRDLOG_ID);            /*read into memory*/
  87.  
  88.     PortBUseP = (char *)(PortBUse);        /* a pointer to PortBUse Byte    */
  89.     SPConfigP = (char *)(SPConfig);        /* a pointer to SerialPortConfiguration byte*/
  90.  
  91.     use = *PortBUseP;                    /* get the data */
  92.  
  93.     con = *SPConfigP;                    /* get the data */
  94.  
  95.  
  96.     if( (con & 0x0F) > useATalk )
  97.     {
  98.         ErrMess = "\pSomething wrong with the port(config).  Exit now!";
  99.         ErrDial();    /* put up error message in dialog */
  100.         return(1); 
  101.     }
  102.  
  103.     if( (use & 0xFF) || ( (use&0x0F) == useATalk) ) 
  104.     {
  105.         /* port is currently closed, open as I like  or it's AppleTalk*/
  106.  
  107.         if( !(IsMPPOpen()) )
  108.         {        
  109.                     
  110.             if( (error = MPPOpen()) != noErr) 
  111.             {
  112.                 ErrMess = "\pSomething wrong with the port(MMP).  Exit now, and restart your system!";
  113.                 ErrDial();    /* put up error message in dialog */
  114.                 return(1);
  115.             }
  116.         }
  117.  
  118.         if( !IsATPOpen() )
  119.         {
  120.             
  121.             if( (error = ATPLoad()) != noErr)
  122.             {
  123.                 ErrMess = "\pSomething wrong with the port(ATP).  Exit now!";
  124.                 ErrDial();    /* put up error message in dialog */
  125.                 return(1);
  126.             }
  127.             
  128.             *PortBUseP |= 0x04;        /* ATP loaded */
  129.             *PortBUseP &= 0x7F;        /* in use set, set = 0 */
  130.         }
  131.         
  132.         if( (error = NBPLoad()) )            /* only on 128 MAC's*/
  133.         {
  134.             if(error != noErr)
  135.             {
  136.                 ErrMess = "\pSomething wrong with the port(NBP).  Exit now!";
  137.                 ErrDial();            /* put up error message in dialog */
  138.                 return(1);
  139.             }
  140.         }        
  141.     }    /* end test on port config and use */
  142.     else
  143.     {
  144.         ErrMess = "\pUse bits not correct";
  145.         ErrDial();
  146.         return(1);
  147.     }
  148.  
  149.     *SPConfigP |= 0x01;                    /* set for appleTalk */
  150.  
  151.     doAlloc();
  152.  
  153.     return;
  154.     
  155. }
  156.  
  157.  
  158. LookUp()
  159. {
  160.  
  161.     /* This function will lookup everything on the current zone.
  162.     */
  163.  
  164.     long                junklong;
  165.     Str255            string,jstr;
  166.     char            *tempstr;
  167.  
  168.     int                myNet,myNode;
  169.     AddrBlock            atpaddrs;            /* a filter of who I receive requests through */
  170.     EntityName        searchEntity;        /* who I should search for during lookup */
  171.  
  172.     Handle            itemHand;
  173.     int                type;
  174.     Rect                SelBox;
  175.  
  176.     int                error;
  177.  
  178.  
  179.     if( atpRec == 0 )
  180.     {
  181.         /* this is only executed the first time it is called */
  182.  
  183.         atpRec = (ABRecHandle)NewHandle(sizeof(ABusRecord));    /* record for the ReceivedRequest  */
  184.  
  185.         RecSocket = MYSOCKET;
  186.  
  187.         atpaddrs.aNet             = (int)0;            /* wild, all */
  188.         atpaddrs.aNode             = (Byte)0;        /* wild, all */
  189.         atpaddrs.aSocket         = (Byte)0;        /* wild, all */
  190.  
  191.         if( (error = ATPOpenSocket(atpaddrs,&RecSocket)) != noErr)
  192.         {
  193.             ErrMess = "\pSomething wrong ATPOpenSocket.";
  194.  
  195.             NumToString( (long)error, string);
  196.             Pappend(ErrMess,string);        /* give me the error number */
  197.  
  198.             ErrDial();
  199.             return(1);        /* for some error control return 1 else return a 0 */
  200.         }
  201.  
  202.         NetReg();                /* register that name and node/socket on net */
  203.     
  204.         if( GetNodeAddress(&myNode,&myNet) != noErr)
  205.         {
  206.             /* I do this only so I can display it on the screen, not necessary normally */
  207.     
  208.             /*    because I have opened the receive socket above I know the
  209.                 InterNet address.
  210.             */
  211.     
  212.             ErrMess = "\pSomething wrong GetNodeAddress";
  213.             ErrDial();
  214.         }
  215.     
  216.         junklong = (myNode);
  217.         NumToString( junklong, jstr);        /* put the node number in a char string */
  218.         Pstrcopy(string,jstr);
  219.         
  220.         tempstr = "\p:";                /* just a colon */
  221.         Pappend(string,tempstr);
  222.     
  223.         junklong = RecSocket;            /* no longer contains a 0 so convert and place in a string*/
  224.         NumToString(junklong,jstr);
  225.         Pappend(string,jstr);            /* add to display string */
  226.     
  227.         tempstr = "\p@";
  228.         Pappend(string,tempstr);
  229.     
  230.         junklong = myNet;
  231.         NumToString(junklong,jstr);
  232.         Pappend(string,jstr);            /* add the net number to the display string */
  233.     
  234.         GetDItem(myWindow,MYNUM,&type,&itemHand,&SelBox);
  235.         SetIText(itemHand,string);        /* display the InterNet Address */
  236.     
  237.     }
  238.     
  239.     /*now that I have my name and node I want to know everyone else */
  240.  
  241.     tempstr = "\p=";                /*wild card for obj and type*/
  242.     Pstrcopy(searchEntity.objStr,tempstr);
  243.  
  244.     Pstrcopy(searchEntity.typeStr,tempstr);
  245.  
  246.     tempstr ="\p*";                        /* wild card for this zone only */
  247.     Pstrcopy(searchEntity.zoneStr,tempstr);        /* what ever this zone is */
  248.  
  249.  
  250.     (**myABRecord).nbpProto.nbpEntityPtr = &searchEntity;    /* set up filter for search of net  */
  251.     (**myABRecord).nbpProto.nbpBufPtr = (Ptr)&LUBuffer[0];        /* used internal by NBP */
  252.     (**myABRecord).nbpProto.nbpBufSize = sizeof(LUBuffer);    /* where the returned names go */
  253.     (**myABRecord).nbpProto.nbpDataField = 100;            /* about 100 node out there??? */
  254.     (**myABRecord).nbpProto.nbpRetransmitInfo.retransInterval = 75;    /* in 8 tick counts, 75 = 10 sec*/
  255.     (**myABRecord).nbpProto.nbpRetransmitInfo.retransCount = 2;    /* set up the retry stuff */
  256.  
  257.     if( (NBPLookup(myABRecord,SYNC) != noErr) )
  258.     {
  259.         ErrMess = "\pSomething wrong NBPLookup. To many node maybe?";
  260.         ErrDial();
  261.     }
  262.  
  263.  
  264.     junklong = (long)(**myABRecord).nbpProto.nbpDataField + 1;
  265.                 /* the .nbpDataField tells you how may named enities were on the net */
  266.  
  267.     if( junklong > 1)
  268.     {
  269.     GetDItem(myWindow,DISPLAYB,&type,&itemHand,&SelBox);
  270.     HiliteControl(itemHand,0);        /*part0, turn on*/
  271.     }
  272.  
  273.     NumToString( junklong, string);
  274.     GetDItem(myWindow,NUMBER,&type,&itemHand,&SelBox);
  275.     SetIText(itemHand,string);            /* display how may */
  276.  
  277.     Extractwhere = 1;    /* start here on extract */
  278.  
  279.     Receive(0);        /* now that someone maybe on the system set up to receive a request */
  280.  
  281.     Receive(1);
  282.     Receive(1);
  283.     Receive(1);
  284.     Receive(1);        /* put in a bunch of request receives in the que */
  285.  
  286.     return(0);        /* good return    */
  287.  
  288. }
  289.  
  290. NetReg()
  291. {
  292.     /* this routine will register the name, type on the net */
  293.  
  294.     Handle            itemHand;
  295.     int                type;
  296.     Rect                SelBox;
  297.     char            *tempstr;
  298.     Str255            string;
  299.     int                error;
  300.  
  301.  
  302.     /* going to set up the name, type, and zone of this Mac */
  303.  
  304.     GetDItem(myWindow,MYNODE,&type,&itemHand,&SelBox);    /*my usr name, set with the chooser */
  305.     GetIText(itemHand,&myEntity.objStr);                    /* put in usr name */
  306.  
  307.     tempstr = "\pGORILLA";                            /* a Ty Shipman Type */
  308.     Pstrcopy(myEntity.typeStr,tempstr);
  309.  
  310.     tempstr = "\p*";                                    /*  current zone */
  311.     Pstrcopy(myEntity.zoneStr,tempstr);
  312.  
  313.     (**myABRecord).nbpProto.nbpEntityPtr        = &myEntity;            /* set up my name */
  314.     (**myABRecord).nbpProto.nbpBufPtr        = (Ptr)&myEBuff;        /* used internal by NBP */
  315.     (**myABRecord).nbpProto.nbpBufSize        = sizeof(myEBuff);
  316.     (**myABRecord).nbpProto.nbpAddress.aSocket    = RecSocket;            /* this can not be allocated on the fly, set be opensocket */
  317.     (**myABRecord).nbpProto.nbpRetransmitInfo.retransInterval = 7;                    /* in seconds */
  318.     (**myABRecord).nbpProto.nbpRetransmitInfo.retransCount    = 1;
  319.  
  320.  
  321.     /* register the name on the system */
  322.     if( (error = NBPRegister(myABRecord,SYNC) ) != noErr)
  323.     {
  324.         ErrMess = "\pSomething wrong with NBPRegister, try a different name.";
  325.         
  326.         NumToString( (long)error, string);
  327.         Pappend(ErrMess,string);        /* give me the error number */
  328.         
  329.         ErrDial();
  330.         return(1);
  331.     }
  332.  
  333.     return(0);
  334.  
  335. }
  336.  
  337. Receive(redo)
  338. int redo;
  339. {
  340.     /* this routine will place a GetRequest in the Que */
  341.  
  342.     int         error;
  343.     Str255    tempstr;
  344.  
  345.     if( redo == 0)
  346.     {
  347.         (**atpRec).atpProto.atpSocket     = RecSocket;
  348.         (**atpRec).atpProto.atpReqCount    = 255;            /* all but the length bypte */
  349.         (**atpRec).atpProto.atpDataPtr    = (Ptr)&atpRecBuf;    /* my sting to store message */
  350.     }
  351.  
  352.      if( (error = ATPGetRequest(atpRec,ASYNC)) != noErr)
  353.     {
  354.         ErrMess = "\pSomething wrong ATPGetRequest.";
  355.  
  356.         NumToString( (long)error, tempstr);
  357.         Pappend(ErrMess,tempstr);
  358.  
  359.         ErrDial();
  360.         return(1);
  361.     }
  362.     return(0);
  363. }
  364.  
  365.  
  366. SendResponce(request)
  367. ABRecHandle     request;
  368. {
  369.     /*    This routine will send a responce to a request from another device.
  370.         The socket I want to send the responce to is contained in the
  371.         request packet.
  372.  
  373.     */
  374.  
  375.     int            error;        /* a temp area */
  376.     Str255        tempstr;
  377.  
  378.     SetupRsp(&RspBDS,BDSmess,256);    /* this routine will copy the message to the BDS specified */
  379.  
  380.  
  381.     (**Responce).atpProto.atpSocket = RecSocket;                                        /* send out the socket in which the request was sent to */
  382.     (**Responce).atpProto.atpAddress.aNet         = (**request).atpProto.atpAddress.aNet;        /* contains the requesting address */
  383.     (**Responce).atpProto.atpAddress.aNode    = (**request).atpProto.atpAddress.aNode;
  384.     (**Responce).atpProto.atpAddress.aSocket    = (**request).atpProto.atpAddress.aSocket;
  385.     (**Responce).atpProto.atpRspBDSPtr = (BDSPtr)&RspBDS;                                        /* pointer to BDS, data should already be in BDS */
  386.     (**Responce).atpProto.atpTransID = (**request).atpProto.atpTransID;
  387.  
  388.     (**Responce).atpProto.atpEOM = TRUE;    /* only one responce here */
  389.     (**Responce).atpProto.atpNumBufs = 1;    /* only one buffer envolved here */
  390.     (**Responce).atpProto.atpBDSSize = 1;
  391.  
  392.  
  393.     if( (error = ATPSndRsp(Responce,SYNC)) != noErr)
  394.     {
  395.         ErrMess = "\pSomething wrong ATPSndRsp.";
  396.  
  397.         NumToString( (long)error, tempstr);
  398.         Pappend(ErrMess,tempstr);
  399.  
  400.         ErrDial();
  401.         return(1);
  402.     }
  403.  
  404.     return(0);
  405. }
  406.  
  407. SetupRsp(BDS,mess,size)
  408. BDSElement    *BDS;        /* pointer to BDSElement that I am to use */
  409. char        *mess;        /* the message I am to copy in */
  410. int            size;        /* the number of bytes to copy into BDS */
  411. {
  412.  
  413.         BDS->buffSize = mess[0] + 1;    /* since there is only one packet, of max 256 bytes, set to size */
  414.         BDS->buffPtr = mess;    /* set pointer to data to be sent to requester */
  415.         /*
  416.         .dataSize     set by reciever of this packet. i.e. the requester
  417.         .userBytes       set by sender in ATP.
  418.         */
  419. }
  420.  
  421.  
  422. Display()
  423. {
  424.     /* this routine will display all nodes/sockets on the screen */
  425.  
  426.         Handle            itemHand;
  427.         int                type;
  428.         Rect                SelBox;
  429.         Str255            currstrg, string;
  430.         char            *tempstr;
  431.  
  432.     if( ((**myABRecord).nbpProto.nbpDataField) <= 0)
  433.         return;        /* just incase there is nothing in the lookup */
  434.  
  435.     if( (NBPExtract( (Ptr)&LUBuffer,(**myABRecord).nbpProto.nbpDataField
  436.                     ,Extractwhere,&(NowEntity.CurName),&(NowEntity.CurAddrs)) )
  437.                     != noErr)
  438.     {
  439.         ErrMess = "\pSomething wrong NBPExtract.";
  440.         ErrDial();
  441.     }
  442.  
  443.     GetDItem(myWindow,SENDB,&type,&itemHand,&SelBox);
  444.     HiliteControl(itemHand,0);        /*part0, turn on*/
  445.  
  446.  
  447.     /* has nothing to do with AppleTalk, just so I can display it on the screen */
  448.         /* uses the standard display format of name : type @ zone */
  449.  
  450.     Pstrcopy(currstrg,NowEntity.CurName.objStr);
  451.     tempstr = "\p:";                        /* the seperator for name and type */
  452.     Pappend(currstrg,tempstr);
  453.     Pappend(currstrg,NowEntity.CurName.typeStr);
  454.     tempstr = "\p@";                        /* the seperator for name and type */
  455.     Pappend(currstrg,tempstr);
  456.     Pappend(currstrg,NowEntity.CurName.zoneStr);
  457.     GetDItem(myWindow,CNODEIS,&type,&itemHand,&SelBox);        /* do the name */
  458.     SetIText(itemHand,currstrg);
  459.  
  460.     NumToString( (long)NowEntity.CurAddrs.aNode, string);
  461.     Pstrcopy(currstrg,string);
  462.     tempstr = "\p•";                    /* just some filler */
  463.     Pappend(currstrg,tempstr);
  464.     NumToString( (long)NowEntity.CurAddrs.aSocket, string);
  465.     Pappend(currstrg,string);
  466.     GetDItem(myWindow,CNODENUM,&type,&itemHand,&SelBox);
  467.     SetIText(itemHand,currstrg);
  468.  
  469.     /* all done with the screen display */
  470.  
  471.     if( (Extractwhere < (**myABRecord).nbpProto.nbpDataField) )
  472.         Extractwhere++;        /* the next time */
  473.     else
  474.         Extractwhere = 1;    /* reset to beginning of list */
  475.         
  476.     return;
  477. }
  478.  
  479.  
  480. Send()
  481. {
  482.     /* this routine will send a request that contains the editable
  483.         text field of the dialog */
  484.  
  485.     int                error;
  486.     Str255            tempstr;
  487.  
  488.     Handle            itemHand;
  489.     int                type;
  490.     Rect                SelBox;
  491.  
  492.     myBDSPtr = (BDSPtr)&myBDS;
  493.  
  494.     myBDSPtr[0]->buffPtr = (Ptr)&mysBuffer[0];    /* buffer that will contain message */
  495.     myBDSPtr[0]->buffSize = 512;
  496.  
  497.     GetDItem(myWindow,SENDM,&type,&itemHand,&SelBox);
  498.     GetIText(itemHand,(Ptr)&mysBuffer[0]);                /* put in message */
  499.  
  500.     (**SendRec).atpProto.atpAddress.aNet     = NowEntity.CurAddrs.aNet;
  501.     (**SendRec).atpProto.atpAddress.aNode    = NowEntity.CurAddrs.aNode;
  502.     (**SendRec).atpProto.atpAddress.aSocket = NowEntity.CurAddrs.aSocket;    /* setup the target address */
  503.  
  504.     (**SendRec).atpProto.atpReqCount = PLength(mysBuffer);
  505.     (**SendRec).atpProto.atpDataPtr = (Ptr)&mysBuffer[0];        /* setup the request data */
  506.     (**SendRec).atpProto.atpRspBDSPtr = (BDSPtr)&myBDSPtr;
  507.  
  508.     (**SendRec).atpProto.atpXO = FALSE;                    /* set to NOT exactly once */
  509.     (**SendRec).atpProto.atpTimeOut = 4;
  510.     (**SendRec).atpProto.atpRetries = 2;
  511.     (**SendRec).atpProto.atpNumBufs = 1;        /* one BDS element */
  512.     (**SendRec).atpProto.atpNumRsp = 0;            /* set to no responces yet */
  513.  
  514.     if( (error = ATPSndRequest(SendRec,ASYNC)) != noErr)
  515.         {
  516.             ErrMess = "\pSomething wrong ATPSndRequest.";
  517.  
  518.             NumToString( (long)error, tempstr);
  519.             Pappend(ErrMess,tempstr);
  520.  
  521.             ErrDial();
  522.             return(1);
  523.         }
  524.  
  525.     Receive(1);        /* post because of when done it will post a request event and
  526.                         use up one GetRequest() */
  527.  
  528.     return(0);        /* no error in this code */
  529. }
  530.  
  531. DoATNet(ParHan)
  532. ABRecHandle     ParHan;        /* a handle to the record generated by AT */
  533. {
  534.         /*    this routine will handle all events generated by the apple talkl
  535.             net work.  The possible events call include:
  536.  
  537.         */
  538.     Handle            itemHand;
  539.     int                type;
  540.     Rect            SelBox;
  541.  
  542.     if( ParHan == SendRec)
  543.     {
  544.         if( (**ParHan).atpProto.atpNumRsp > 0)
  545.         {
  546.             /* here is where you would process the responce */
  547.         }
  548.         /* no responce, the responder is out ??? */
  549.     }
  550.     else if( ParHan == atpRec)
  551.     {
  552.     GetDItem(myWindow,RECM,&type,&itemHand,&SelBox);
  553.     SetIText(itemHand,((**ParHan).atpProto.atpDataPtr) );
  554.  
  555.     SendResponce(ParHan);    /* send responce to requester */
  556.     }
  557.  
  558.     Receive(1);        /* now that a message has come in set up for another */
  559.  
  560.     return(0);
  561.  
  562. }
  563.  
  564. CloseAT()
  565. {
  566.         /* this routine will clean up the frame and glb area */
  567.  
  568.         int        error;
  569.         Str255    tempstr;
  570.  
  571.     if(  (RecSocket != 0) && (error = ATPCloseSocket(RecSocket) != noErr)   )                /* for the receive socket */
  572.     {
  573.         ErrMess = "\pSomething wrong ATPCloseSocket.  ";
  574.  
  575.         NumToString( (long)error, tempstr);
  576.         Pappend(ErrMess,tempstr);
  577.  
  578.         ErrDial();
  579.         return(1);
  580.     }
  581.  
  582.     NBPRemove(&myEntity);                    /* remove from net */
  583.  
  584.     if( SendRec != 0)
  585.     {
  586.         ATPReqCancel(SendRec,((Boolean)FALSE));    /* for send socket, async */
  587.     }
  588.  
  589.     if( atpRec != 0)
  590.         DisposHandle(atpRec);
  591.  
  592.     if( myABRecord != 0)
  593.         DisposHandle(myABRecord);
  594.  
  595.     if( Responce != 0)
  596.         DisposHandle(Responce);
  597.  
  598.     if( SendRec != 0)
  599.         DisposHandle(SendRec);
  600.  
  601.     return(0);    /* good return */
  602.  
  603. }
  604.  
  605.  
  606. ErrDial()
  607. {
  608.     /* this routine puts up a dialog box with the error in it
  609.         the error message is contained in a global
  610.         the error dialog stay up until a mouse down occures
  611.     */
  612.  
  613.     Handle            itemHand;
  614.     int                type;
  615.     Rect                SelBox;
  616.     DialogPtr            errorWindow;
  617.     WindowPtr        oldport;
  618.  
  619.     GetPort(&oldport);
  620.     
  621.     errorWindow = GetNewDialog(ERRDLOG_ID,NIL,(WindowPtr)-1);
  622.  
  623.     SetPort(errorWindow);
  624.     
  625.     GetDItem(errorWindow,ERRMESS,&type,&itemHand,&SelBox);
  626.  
  627.     SetIText(itemHand,ErrMess);
  628.  
  629.     FrameRect(&SelBox);
  630.  
  631.     GetDItem(errorWindow,2,&type,&itemHand,&SelBox);
  632.     ErrMess = "\pClick Mouse to Continue";
  633.     SetIText(itemHand,ErrMess);
  634.  
  635.  
  636.     do {
  637.     } while ( !Button() );            /* just click to make go away */
  638.  
  639.     CloseDialog(errorWindow);        /* make go away */
  640.  
  641.     SetPort(oldport);
  642.     
  643.     return;
  644. }
  645.  
  646.  
  647. int
  648. PLength(strPtr)
  649. unsigned char *strPtr;
  650. {
  651.     /*this routine returns the length of the pascal string*/
  652.  
  653.     return( ((int)strPtr[0] + 1) );    /* the first byte is the length */
  654. }
  655.  
  656.  
  657. Pstrcopy(dest,sour)
  658. unsigned     char    *dest, *sour;
  659. {
  660.     dest[0] = 0;    /* no string in there    */
  661.     Pappend(dest,sour);
  662.     
  663.     return(0);
  664. }
  665.  
  666. Pappend(dest,sour)
  667. unsigned     char    *dest, *sour;
  668. {
  669.         /*    this routine will copy the 'C' string at sour to a P string at dest */
  670.         /*    NOTE:    the dest char array should be declared static to insure you don't fucked results */
  671.         int        loop;
  672.         int     dlen,slen;
  673.         
  674.         slen = (int)sour[0];        /* the length of the string*/     
  675.         dlen = (int)dest[0];        /* not include the length byte */
  676.         
  677.         slen = ( (dlen + slen) <= 255) ? slen : 255 - dlen;        /* not over the stupid limit */
  678.         
  679.         dest[0] += slen;            /* new length of stuff */
  680.         
  681.         dest += dlen;                /* get to end of stuff */
  682.         
  683.         sour++;                        /* get past the length byte */
  684.         dest++;                            /* same */        
  685.             
  686.         BlockMove(sour,dest,(long)slen);            
  687.             
  688.         return(0);
  689.         
  690. }